package com.gylang.print.richtext.append;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.gylang.api.CommConstant;
import org.apache.commons.collections4.MultiSet;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
import org.jsoup.nodes.Element;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author gylang
 * data 2021/7/8
 */
public interface IRichAppend {


	/**
	 * 渲染富文本html
	 *
	 * @param element 节点
	 * @param data    数据
	 * @return
	 */
	Element append(Element element, Map<String, Object> data);


	/**
	 * 通用替换占位符
	 *
	 * @param data    占位替换数据
	 * @param element 当前标签
	 */
	default void replaceAll(Map<String, Object> data, Element element) {
		List<String> placeHolders = ReUtil.findAllGroup1(CommConstant.POINT_MODE_PLACEHOLDER, element.text());
		if (CollUtil.isEmpty(placeHolders)) {
			return;
		}

		Element parent = element;
		List<String> textList = replacePlaceHolderList(placeHolders, element, data);
		if (CollUtil.isNotEmpty(textList)) {
			for (String s : textList) {
				parent.after(s);
				parent = parent.nextElementSibling();
			}
		}
		element.remove();
	}

	/**
	 * 获取bean形式的占位替换后的列表
	 *
	 * @param placeHolders 占位符列表 xxx.aaa
	 * @param element      当前标签
	 * @param data         占位替换数据
	 * @return 返回结果
	 */
	default List<String> replacePlaceHolderList(List<String> placeHolders, Element element, Map<String, Object> data) {

		// 提取数据 判断是否为集合 集合则进行遍历渲染 非集合就转map

		// 1 获取所有对象的首位
		MultiValuedMap<String, String> multiValuedMap = new HashSetValuedHashMap<>();
		for (String placeHolder : placeHolders) {
			String beanName = StrUtil.subBefore(placeHolder, ".", false);
			multiValuedMap.put(beanName, placeHolder);
		}
		// 判断当前bean的类型 并讲转成map<String, Object>
		Map<String, List<Map<String, Object>>> dataList = resolveDataList(multiValuedMap.keys(), data);
		int maxLine = dataList.values().stream().mapToInt(List::size).max().orElse(0);

		List<Map<String, Object>> formatDataList = merge(dataList, maxLine);
		String text = element.outerHtml();
		List<String> tagList = new ArrayList<>();
		for (int i = 0; i < maxLine; i++) {
			// to -> bean.field
			String newNode = StrUtil.format(text, formatDataList.get(i));
			tagList.add(newNode);
		}

		return tagList;
	}

	/**
	 * 合并多个bean list的数据
	 *
	 * @param dataListMap 数据
	 * @param maxLine     bean 列表中最大长度
	 * @return 合并后的数据
	 */
	default List<Map<String, Object>> merge(Map<String, List<Map<String, Object>>> dataListMap, int maxLine) {

		List<Map<String, Object>> listMap = new ArrayList<>();
		Collection<List<Map<String, Object>>> listCollection = dataListMap.values();
		for (int i = 0; i < maxLine; i++) {
			Map<String, Object> data = new HashMap<>();
			listMap.add(data);
			for (List<Map<String, Object>> maps : listCollection) {
				if (i < maps.size()) {
					data.putAll(maps.get(i));
				}
			}
		}
		return listMap;
	}

	/**
	 * 合并数据 讲数据以行的形式合并 同行为一行
	 *
	 * @param beanNames 数据bean的名称
	 * @param data      真实数据
	 * @return
	 */
	default Map<String, List<Map<String, Object>>> resolveDataList(MultiSet<String> beanNames, Map<String, Object> data) {
		Map<String, List<Map<String, Object>>> dataList = new HashMap<>();
		// 遍历数据进行合并
		for (String beanName : beanNames) {

			Object o = data.get(beanName);
			if (ObjectUtil.isEmpty(o)) {
				continue;
			}
			if (o instanceof Collection) {
				// 集合类型数据 对数据进行拆解转map
				@SuppressWarnings("unchecked") Collection<Object> collection = (Collection) o;
				if (ClassUtil.isSimpleValueType(CollUtil.getElementType(collection))) {
					// 集合元素为简单类型 string 和基本数据类型 日期...
					List<Map<String, Object>> beanList = collection.stream().map(base -> Collections.singletonMap(beanName, base)).collect(Collectors.toList());
					dataList.put(beanName, beanList);
				} else {
					// 集合原始为bean 将bean转map
					List<Map<String, Object>> beanList = collection.stream().map(BeanUtil::beanToMap).collect(Collectors.toList());
					beanList = beanList.stream()
						.map(m -> m.entrySet().stream().collect(Collectors.toMap(k -> beanName + "." + k.getKey(), Map.Entry::getValue)))
						.collect(Collectors.toList());
					dataList.put(beanName, beanList);
				}
			} else if (ClassUtil.isSimpleValueType(o.getClass())) {
				// 简单类型数据
				List<Map<String, Object>> maps = CollUtil.newArrayList(Collections.singletonMap(beanName, o));
				dataList.put(beanName, maps);
			} else {
				// bean形式的数据
				List<Map<String, Object>> maps = CollUtil.newArrayList(BeanUtil.beanToMap(o));
				maps = maps.stream()
					.map(m -> m.entrySet().stream().collect(Collectors.toMap(k -> beanName + "." + k.getKey(), Map.Entry::getValue)))
					.collect(Collectors.toList());
				dataList.put(beanName, maps);
			}
		}
		return dataList;
	}
}
